<?php
namespace Tlf\Tester;
/**
* Convenience methods for database work
*/
trait Databasing {
/**
* Create a pdo mysql instance by loading db settings from a file.
* File should contain `mysql.dbname`, `mysql.host`, `mysql.user`, and `mysql.password`
* @param $json_file_path a path to a json file
* @return a PDO instance
*/
public function getPdoFromSettingsFile(string $json_file_path): \PDO {
$settings = json_decode(file_get_contents($json_file_path),true);
$pdo = new \PDO('mysql:dbname='.$settings['mysql.dbname'].';host='.$settings['mysql.host'],
$settings['mysql.user'],$settings['mysql.password']);
return $pdo;
}
public function getPdo($dbName = ':memory:'){
$pdo = new \PDO('sqlite:'.$dbName);
return $pdo;
}
/**
* Perform a query and return the rows
*
* @param $pdo a pdo instance
* @param $sql an sql string
* @param $where_cols values to bind to the sql string
* @return an associative array of the first row
*/
public function dbQuery(\PDO $pdo, string $sql, array $where_cols = []){
$stmt = $pdo->prepare($sql);
$stmt->execute($where_cols);
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
/**
* Select a single row by id
* @param $pdo a PDO instance
* @param $table the table name
* @param $id the id to query for
*
* @return the row
*/
public function dbSelectById(\PDO $pdo, string $table, int $id){
$stmt = $pdo->prepare("SELECT * FROM `{$table}` WHERE id = {$id}");
$stmt->execute();
return $stmt->fetchAll(\PDO::FETCH_ASSOC)[0];
}
/**
* DELETE a single row by id
* @param $pdo a PDO instance
* @param $table the table name
* @param $id the id to query for
* @return num rows affected
*/
public function dbDeleteById(\PDO $pdo, string $table, int $id){
$stmt = $pdo->prepare("DELETE FROM `{$table}` WHERE id = {$id}");
$stmt->execute();
// return $stmt->fetchAll(\PDO::FETCH_ASSOC)[0];
return $stmt->rowCount();
}
/**
* Insert a row into the database
* @param $pdo a PDO instance
* @param $tableName a string table name
* @param $values an array of key=>value pairs
* @return The inserted row (queries DB by id for the row AFTER the insert)
*/
public function dbInsert($pdo, $tableName, $values){
$cols = [];
$binds = [];
foreach ($values as $key=>$value){
$cols[] = $key;
$binds[":{$key}"] = $value;
}
$colsStr = '`'.implode('`, `',$cols).'`';
$bindsStr = implode(', ', array_keys($binds));
$query = "INSERT INTO `${tableName}`(${colsStr})
VALUES (${bindsStr})
";
$stmt = $pdo->prepare($query);
if ($stmt===false){
echo "PDO ErrorInfo:\n";
print_r($pdo->errorInfo());
// echo "\n";
// return;
throw new \Exception("Could not insert values into databse.");
}
$stmt->execute($binds);
return $this->dbSelectById($pdo, $tableName, $pdo->lastInsertId());
}
public function dbInsertAll($pdo, $tableName, $rows){
$cols = [];
$binds = [];
$query = '';
foreach ($rows as $index=>$row){
$new_bind_keys = [];
foreach ($row as $key=>$value){
$binds[":{$key}_$index"] = $value;
$new_bind_keys[] = ":{$key}_$index";
}
$bindsStr = implode(', ', $new_bind_keys);
if ($index!=0)$query .=",\n";
$query .= "(${bindsStr})";
}
foreach (array_slice($rows,0,1)[0] as $key=>$value){
$cols[] = $key;
}
$colsStr = '`'.implode('`, `',$cols).'`';
$query = "INSERT INTO `${tableName}`(${colsStr})
VALUES $query
";
$stmt = $pdo->prepare($query);
if ($stmt===false){
echo "PDO ErrorInfo:\n";
print_r($pdo->errorInfo());
// echo "\n";
// return;
throw new \Exception("Could not insert rows into databse.");
}
$stmt->execute($binds);
return $this->dbSelectById($pdo, $tableName, $pdo->lastInsertId());
}
/**
* @param array $cols array of columns like: `['col_name'=>'VARCHAR(80)', 'col_two'=> 'integer']`
*/
public function createTable(\PDO $pdo, string $tableName, array $cols, bool $dropIfExists=false){
$colStatements = [];
foreach ($cols as $col => $definition){
$statement = '`'.$col.'` '. $definition;
$colStatements[] = $statement;
}
$colsSql = implode(", ", $colStatements);
$drop = $dropIfExists ? "DROP TABLE IF EXISTS `{$tableName}`;\n" : '';
$sql =
<<<SQL
{$drop}
CREATE TABLE `{$tableName}`
(
{$colsSql}
)
;
SQL;
$this->dbExec($pdo, $sql);
}
/**
* Returns the first row from the query result.
* @todo don't fetchAll(). Only fetch first row.
*/
public function queryOne(\PDO $pdo, string $sql, ?array $binds=null): ?array{
$rows = $this->query($pdo, $sql, $binds);
return $rows[0] ?? null;
}
public function query(\PDO $pdo, string $sql, ?array $binds=null): array{
$pdo = $pdo;
$stmt = $pdo->prepare($sql);
if ($stmt===false){
var_dump($pdo->errorInfo());
throw new \Exception("Sql problem.");
}
$stmt->execute($binds);
$rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
return $rows;
}
public function dbExec($pdo, $sql, $binds=[]){
$stmt = $pdo->prepare($sql);
if ($stmt===false){
var_dump($pdo->errorInfo());
throw new \Exception("Sql problem.");
}
$stmt->execute($binds);
}
}